using System.Windows;
using System.Windows.Controls.Primitives;
using FireStarterModeller.Logic.Commands;
using FireStarterModeller.UI.DetailsView;
using FireStarterModeller.UI.DetailsView.Controller;
using FireStarterModeller.UI.DetailsView.WPF;
using Habanero.Util;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.UI.DetailsView.WPF
{
    [TestFixture]
    public class TestSolutionView
    {
        [Test]
        public void Test_Init()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel model = new SolutionViewModel("ModelName");
                     SolutionView solutionView = new SolutionView();
                     ISolutionViewController controller = CreateController(model);

                     //---------------Execute Test ----------------------
                     solutionView.Init(controller, model);

                     //---------------Test Result -----------------------
                     Assert.AreSame(controller, solutionView.Controller);
                     Assert.AreSame(model, solutionView.Model);

                     //---------------Tear Down -------------------------          
                 });
        }

        //Display solution with one assembly
        [Test]
        public void Test_Display_OneAssembly()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
                     SolutionViewModel.AssemblyModel assemblyModel1 = new SolutionViewModel.AssemblyModel("Assembly1");
                     solutionViewModel.Assemblies.Add(assemblyModel1);
                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();

                     //---------------Execute Test ----------------------
                     solutionView.Init(controller, solutionViewModel);

                     //---------------Test Result -----------------------
                     Assert.AreEqual(1, solutionView.AssembliesStackPanel.Children.Count);
                     SolutionAssemblyView assemblyView1 =
                         (SolutionAssemblyView) (solutionView.AssembliesStackPanel.Children[0]);
                     Assert.AreSame(assemblyModel1, assemblyView1.Model);
                 });
        }

        //Display solution with multiple assemblies
        [Test]
        public void Test_Display_TwoAssemblies()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel.AssemblyModel assemblyModel2;
                     SolutionViewModel solutionViewModel = GetSolutionViewModel_2Assemblies(out assemblyModel2);
                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();

                     //---------------Execute Test ----------------------
                     solutionView.Init(controller, solutionViewModel);

                     //---------------Test Result -----------------------
                     Assert.AreEqual(2, solutionView.AssembliesStackPanel.Children.Count);
                     SolutionAssemblyView assemblyView2 =
                         (SolutionAssemblyView) (solutionView.AssembliesStackPanel.Children[1]);
                     Assert.AreSame(assemblyModel2, assemblyView2.Model);
                 });
        }

        //Select assembly
        [Test]
        public void Test_CurrentAssembly_SelectedOnInit()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
                     SolutionViewModel.AssemblyModel assemblyModel = AddAssembly(solutionViewModel, "Assembly1");

                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();

                     //---------------Assert PreConditions---------------  
                     Assert.AreSame(assemblyModel, solutionViewModel.CurrentAssembly);

                     //---------------Execute Test ----------------------
                     solutionView.Init(controller, solutionViewModel);
                     //---------------Test Result -----------------------
                     SolutionAssemblyView assemblyView =
                         (SolutionAssemblyView) solutionView.AssembliesStackPanel.Children[0];
                     Assert.IsTrue(assemblyView.IsSelected);
                     //---------------Tear Down -------------------------         
                 });
        }


        //Select assembly
        [Test]
        public void Test_CurrentAssemblyChanged_SelectsAssemblyView()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
                     AddAssembly(solutionViewModel, "Assembly1");
                     SolutionViewModel.AssemblyModel assemblyModel2 = AddAssembly(solutionViewModel, "Assembly2");
                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();
                     solutionView.Init(controller, solutionViewModel);

                     SolutionAssemblyView assemblyView1 =
                         (SolutionAssemblyView) solutionView.AssembliesStackPanel.Children[0];
                     SolutionAssemblyView assemblyView2 =
                         (SolutionAssemblyView) solutionView.AssembliesStackPanel.Children[1];

                     //---------------Assert PreConditions---------------  
                     Assert.IsTrue(assemblyView1.IsSelected);
                     Assert.IsFalse(assemblyView2.IsSelected);

                     //---------------Execute Test ----------------------
                     solutionViewModel.CurrentAssembly = assemblyModel2;

                     //---------------Test Result -----------------------
                     Assert.IsFalse(assemblyView1.IsSelected);
                     Assert.IsTrue(assemblyView2.IsSelected);

                     //---------------Tear Down -------------------------         
                 });
        }

        //Create assembly
        [Test]
        public void Test_AssemblyAddedToModel_UpdatesDisplay()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
                     AddAssembly(solutionViewModel, "Assembly1");
                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();
                     solutionView.Init(controller, solutionViewModel);

                     //---------------Assert PreConditions---------------         
                     Assert.AreEqual(1, solutionView.AssembliesStackPanel.Children.Count);

                     //---------------Execute Test ----------------------
                     SolutionViewModel.AssemblyModel assemblyModel2 = AddAssembly(solutionViewModel, "Assembly2");

                     //---------------Test Result -----------------------
                     Assert.AreEqual(2, solutionView.AssembliesStackPanel.Children.Count);
                     SolutionAssemblyView assemblyView2 =
                         (SolutionAssemblyView) solutionView.AssembliesStackPanel.Children[1];
                     Assert.AreSame(assemblyModel2, assemblyView2.Model);
                 });
        }

        //Create assembly
        [Test]
        public void Test_CreateAssembly()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("Solution1");
                     MockRepository mock = new MockRepository();
                     ISolutionViewController controller = MockRepository.GenerateStub<ISolutionViewController>();
                     SolutionView solutionView = new SolutionView();
                     solutionView.BeginInit();
                     solutionView.Init(controller, solutionViewModel);
                     const string assemblyName = "Assembly2";
                     //ButtonAutomationPeer buttonAutomationPeer = new ButtonAutomationPeer(solutionView.NewAssemblyButton);
                     //IInvokeProvider provider = buttonAutomationPeer;
                     RoutedEventArgs clickEventArgs = new RoutedEventArgs(ButtonBase.ClickEvent);

                     //---------------Set up expectations----------------
                     controller.Expect(viewController => viewController.CreateAssembly(assemblyName));
                     mock.ReplayAll();

                     //---------------Execute Test ----------------------
                     solutionView.CreateAssembly(assemblyName);

                     //---------------Test Result -----------------------
                     mock.VerifyAll();
                 });
        }

        //Create assembly
        //Delete assembly
        [Test]
        public void Test_AssemblyRemovedFromModel_UpdatesDisplay()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
                     SolutionViewModel.AssemblyModel assemblyModel = AddAssembly(solutionViewModel, "Assembly1");
                     ISolutionViewController controller = CreateController(solutionViewModel);
                     SolutionView solutionView = new SolutionView();
                     solutionView.Init(controller, solutionViewModel);

                     //---------------Assert PreConditions---------------         
                     Assert.AreEqual(1, solutionView.AssembliesStackPanel.Children.Count);

                     //---------------Execute Test ----------------------
                     solutionViewModel.Assemblies.Remove(assemblyModel);

                     //---------------Test Result -----------------------
                     Assert.AreEqual(0, solutionView.AssembliesStackPanel.Children.Count);
                 });
        }


        //Delete assembly
        [Test]
        public void Test_DeleteAssembly()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel model = new SolutionViewModel("Solution1");
                     SolutionViewModel.AssemblyModel assemblyModel = new SolutionViewModel.AssemblyModel("Assembly1");
                     model.Assemblies.Add(assemblyModel);

                     MockRepository mock = new MockRepository();
                     ISolutionViewController controller = MockRepository.GenerateStub<ISolutionViewController>();

                     SolutionView solutionView = new SolutionView();
                     solutionView.Init(controller, model);

                     //--------------Setup expectations------------------
                     controller.Expect(viewController => viewController.DeleteAssembly(assemblyModel));
                     mock.ReplayAll();

                     //---------------Execute Test ----------------------
                     solutionView.DeleteAssembly(assemblyModel); // TODO: figure out how to test context menus

                     //---------------Test Result -----------------------
                     mock.VerifyAll();
                 });
        }


        //Rename assembly
        [Test]
        public void Test_RenameAssembly()
        {
            CrossThreadRunner runner = new CrossThreadRunner();
            runner.RunInSTA
                (() =>
                 {
                     //---------------Set up test pack-------------------
                     SolutionViewModel model = new SolutionViewModel("Solution1");
                     SolutionViewModel.AssemblyModel assemblyModel = new SolutionViewModel.AssemblyModel("Assembly1");
                     model.Assemblies.Add(assemblyModel);
                     const string newName = "NewNane";

                     MockRepository mock = new MockRepository();
                     ISolutionViewController controller = MockRepository.GenerateStub<ISolutionViewController>();

                     SolutionView solutionView = new SolutionView();
                     solutionView.Init(controller, model);

                     //--------------Setup expectations------------------
                     controller.Expect(viewController => viewController.RenameAssembly(assemblyModel, newName));
                     mock.ReplayAll();

                     //---------------Execute Test ----------------------
                     solutionView.RenameAssembly(assemblyModel, newName); // TODO: figure out how to test context menus

                     //---------------Test Result -----------------------
                     mock.VerifyAll();
                 });
        }


        private static SolutionViewController CreateController(SolutionViewModel solutionViewModel)
        {
            return new SolutionViewController(new CommandFactory(), new CommandRunner(), solutionViewModel);
        }

        private static SolutionViewModel.AssemblyModel AddAssembly
            (SolutionViewModel solutionViewModel, string assemblyName)
        {
            SolutionViewModel.AssemblyModel assemblyModel = new SolutionViewModel.AssemblyModel(assemblyName);
            solutionViewModel.Assemblies.Add(assemblyModel);
            return assemblyModel;
        }


        private static SolutionViewModel GetSolutionViewModel_2Assemblies
            (out SolutionViewModel.AssemblyModel assemblyModel2)
        {
            SolutionViewModel solutionViewModel = new SolutionViewModel("MySolution");
            SolutionViewModel.AssemblyModel assemblyModel1 = new SolutionViewModel.AssemblyModel("Assembly1");
            solutionViewModel.Assemblies.Add(assemblyModel1);
            assemblyModel2 = new SolutionViewModel.AssemblyModel("Assembly2");
            solutionViewModel.Assemblies.Add(assemblyModel2);
            return solutionViewModel;
        }
    }
}